/*
 * Copyright 2009 Eat Local Food, LLC
 * Copyright (c) 2007 osCommerce (this file was written after
 * code review of osCommerce).
 *
 * This file is part of gwtCommerce.
 *
 * gwtCommerce is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * gwtCommerce is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with gwtCommerce.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.elf.gwt.store.client.components;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import com.elf.gwt.common.client.components.CommonSimpleComponent;
import com.elf.gwt.common.client.exception.TooManyItemsInCartException;
import com.elf.gwt.common.client.model.AttributeModel;
import com.elf.gwt.common.client.model.AttributeValueModel;
import com.elf.gwt.common.client.model.CategoryModel;
import com.elf.gwt.common.client.model.DetailedProductModel;
import com.elf.gwt.common.client.model.PriceBreakModel;
import com.elf.gwt.common.client.model.ProductMetaModel;
import com.elf.gwt.common.client.model.ProductModel;
import com.elf.gwt.common.client.model.ProductReviewModel;
import com.elf.gwt.common.client.utils.CommonUtils;
import com.elf.gwt.store.client.StoreComponentController;
import com.elf.gwt.store.client.utils.StoreUtils;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 *  
 */
public class ProductComponent extends JSONServerComponent
{	
	protected int maxHeight = 600;
	ProductMetaModel productMetaModel;
	protected DetailedProductModel productModel;
	protected List<String> images;
	protected List<String[]> imageSizes;
	protected NumberFormat fmt;
	protected VerticalPanel bodyPanel;
	protected Grid headingPanel;
	protected InlineHTML nameLabel;
	protected InlineHTML priceLabel;
	protected Grid priceGrid;
	protected Image image;
	protected Image dialogImage;
	protected VerticalPanel verticalImagePanel;
	protected InlineHTML image0Label;
	protected InlineHTML image1Label;
	protected InlineHTML image2Label;
	protected InlineHTML image3Label;
	protected InlineHTML image4Label;
	protected InlineHTML image5Label;
	protected InlineHTML image6Label;
	protected FlowPanel imagesSelectionPanel;

	protected InlineHTML descriptionLabel;
	protected VerticalPanel optionsPanel;
	protected TextBox quantityTextBox;
	protected List<ListBox> optionsListBoxList;
	protected HashMap<String, AttributeValueModel> optionsHash;
	protected HorizontalPanel prevNextPanelTop;
	protected PushButton prevButtonTop;
	protected PushButton nextButtonTop;
	protected HorizontalPanel prevNextPanelBot;
	protected PushButton prevButtonBot;
	protected PushButton nextButtonBot;
	protected int prevProductId;
	protected int nextProductId;
	protected InlineLabel dateAvailableLabel;
	protected InlineLabel dateAddedLabel;
	protected Anchor urlAnchor;
	protected InlineHTML numberOfReviewsHTML;
	protected Image reviewImage;

	protected TellAFriendComponent tellAFriendComponent = null;
	protected ManufacturerInfoComponent manufacturerInfoComponent = null;
	protected AlsoPurchasedComponent alsoPurchasedComponent = null;
	protected ProductXSellComponent productXSellComponent = null;

	/**
	 * Constructor
	 */
	public ProductComponent(StoreComponentController controller, String stylePrefix)
	{
		super(controller, stylePrefix, null, false);
		productModel = new DetailedProductModel(0, 0, "");

		manufacturerInfoComponent = (ManufacturerInfoComponent)controller.getComponent("ManufacturerInfoComponent");
		tellAFriendComponent = (TellAFriendComponent)controller.getComponent("TellAFriendComponent");
		alsoPurchasedComponent = (AlsoPurchasedComponent)controller.getComponent("AlsoPurchasedComponent");
		productXSellComponent = (ProductXSellComponent)controller.getComponent("ProductXSellComponent");

		fmt = NumberFormat.getPercentFormat();
		bodyPanel = new VerticalPanel();
		bodyPanel.setWidth("100%");
		bodyPanel.addStyleName(getHandle() + "BodyPanel");

		//Prev/Next
		prevNextPanelTop = new HorizontalPanel();
		prevNextPanelBot = new HorizontalPanel();

		//Name, Model and Price
		headingPanel = new Grid(2,2);
		headingPanel.addStyleName(getHandle() + "Heading");
		headingPanel.getCellFormatter().setHorizontalAlignment(0, 1, HasHorizontalAlignment.ALIGN_RIGHT);
		headingPanel.getCellFormatter().setVerticalAlignment(0, 0, HasVerticalAlignment.ALIGN_TOP);
		headingPanel.getCellFormatter().setVerticalAlignment(0, 1, HasVerticalAlignment.ALIGN_TOP);
		nameLabel = new InlineHTML();
		priceLabel = new InlineHTML();
		priceLabel.addStyleName(getHandle() + "Price");
		headingPanel.setWidget(0, 0, nameLabel);

		//Product Description
		FlowPanel descriptionPanel = new FlowPanel();
		descriptionPanel.addStyleName(getHandle() + "Description");
		descriptionLabel = new InlineHTML();

		//Product Image
		verticalImagePanel = new VerticalPanel();
		verticalImagePanel.addStyleName("ComponentLink");
		verticalImagePanel.addStyleName("FloatRight");
		verticalImagePanel.setSpacing(4);
		image = new Image();
		image.addClickHandler(imageClickHandler);
		verticalImagePanel.add(image);
		InlineLabel imageDialogLabel = new InlineLabel(controller.getStoreConstants().ProductComponentImageDialogText());
		imageDialogLabel.addClickHandler(imageClickHandler);
		verticalImagePanel.add(imageDialogLabel);
		verticalImagePanel.setCellHorizontalAlignment(imageDialogLabel, HasHorizontalAlignment.ALIGN_CENTER);
		imagesSelectionPanel = new FlowPanel();

		image0Label = new InlineHTML("1");
		image0Label.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				image.setUrl(StoreUtils.getImageProductsDirectory() + images.get(0));
				String[] imageSize = imageSizes.get(0);
				image.setSize(imageSize[0], imageSize[1]);
			}
		});
		imagesSelectionPanel.add(image0Label);

		image1Label = new InlineHTML("&nbsp;2");
		image1Label.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				image.setUrl(StoreUtils.getImageProductsDirectory() + images.get(1));
				String[] imageSize = imageSizes.get(1);
				image.setSize(imageSize[0], imageSize[1]);
			}
		});
		imagesSelectionPanel.add(image1Label);

		image2Label = new InlineHTML("&nbsp;3");
		image2Label.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				image.setUrl(StoreUtils.getImageProductsDirectory() + images.get(2));
				String[] imageSize = imageSizes.get(2);
				image.setSize(imageSize[0], imageSize[1]);
			}
		});
		imagesSelectionPanel.add(image2Label);

		image3Label = new InlineHTML("&nbsp;4");
		image3Label.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				image.setUrl(StoreUtils.getImageProductsDirectory() + images.get(3));
				String[] imageSize = imageSizes.get(3);
				image.setSize(imageSize[0], imageSize[1]);
			}
		});
		imagesSelectionPanel.add(image3Label);

		image4Label = new InlineHTML("&nbsp;5");
		image4Label.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				image.setUrl(StoreUtils.getImageProductsDirectory() + images.get(4));
				String[] imageSize = imageSizes.get(4);
				image.setSize(imageSize[0], imageSize[1]);
			}
		});
		imagesSelectionPanel.add(image4Label);

		image5Label = new InlineHTML("&nbsp;6");
		image5Label.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				image.setUrl(StoreUtils.getImageProductsDirectory() + images.get(5));
				String[] imageSize = imageSizes.get(5);
				image.setSize(imageSize[0], imageSize[1]);
			}
		});
		imagesSelectionPanel.add(image5Label);

		image6Label = new InlineHTML("&nbsp;7");
		image6Label.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				image.setUrl(StoreUtils.getImageProductsDirectory() + images.get(6));
				String[] imageSize = imageSizes.get(2);
				image.setSize(imageSize[0], imageSize[1]);
			}
		});
		imagesSelectionPanel.add(image6Label);
		verticalImagePanel.add(imagesSelectionPanel);

		descriptionPanel.add(verticalImagePanel);
		descriptionPanel.add(descriptionLabel);

		//Product Options
		optionsPanel = new VerticalPanel();
		optionsPanel.addStyleName(getHandle() + "Options");

		//URL
		urlAnchor = new Anchor();
		urlAnchor.setTarget("_blank");

		//Quantity
		Grid quantityPanel = new Grid(1,2);
		quantityTextBox = new TextBox();
		quantityTextBox.setWidth("60px");
		quantityPanel.setText(0,0, controller.getStoreConstants().ProductComponentQuantity());
		quantityPanel.setWidget(0, 1, quantityTextBox);

		//Buttons
		Button reviewsButton = new Button(controller.getStoreConstants().ProductComponentReviews(), reviewsClickHandler);
		reviewsButton.addStyleName(getHandle() + "reviewsButton");

		Button addToCartButton = new Button(controller.getStoreConstants().ProductCompnentAddToCart(), cartClickHandler);
		addToCartButton.addStyleName(getHandle() + "AddToCartButton");

		HorizontalPanel buttonRow = new HorizontalPanel();
		buttonRow.setWidth("100%");
		buttonRow.add(reviewsButton);
		buttonRow.add(addToCartButton);
		buttonRow.setCellHorizontalAlignment(addToCartButton, HasHorizontalAlignment.ALIGN_RIGHT);

		//Date Added
		dateAvailableLabel = new InlineLabel("replace");
		dateAvailableLabel.setStyleName("WarningLabel");
		dateAddedLabel = new InlineLabel("replace");

		//Add to Display Panel
		bodyPanel.add(prevNextPanelTop);
		bodyPanel.setCellHorizontalAlignment(prevNextPanelTop, HasHorizontalAlignment.ALIGN_CENTER);
		bodyPanel.add(headingPanel);
		bodyPanel.add(descriptionPanel);
		bodyPanel.add(urlAnchor);
		bodyPanel.add(optionsPanel);

		VerticalPanel quantityButtonPanel = new VerticalPanel();
		quantityButtonPanel.setStyleName(getHandle() + "QuantityAndButtons");
		quantityButtonPanel.setWidth("100%");
		quantityButtonPanel.add(quantityPanel);
		quantityButtonPanel.add(buttonRow);
		quantityButtonPanel.setCellHorizontalAlignment(quantityPanel, HasHorizontalAlignment.ALIGN_RIGHT);

		bodyPanel.add(quantityButtonPanel);
		FlowPanel reviewPanel = new FlowPanel();
		numberOfReviewsHTML = new InlineHTML();
		reviewImage = new Image();
		reviewPanel.add(numberOfReviewsHTML);
		reviewPanel.add(reviewImage);
		reviewPanel.add(new InlineHTML("<br/><br/>"));
		bodyPanel.add(reviewPanel);
		bodyPanel.add(dateAvailableLabel);
		bodyPanel.add(dateAddedLabel);
		bodyPanel.add(new InlineHTML("<br/>"));
		bodyPanel.add(prevNextPanelBot);
		bodyPanel.add(new InlineHTML("<br/>"));
		bodyPanel.setCellHorizontalAlignment(prevNextPanelBot, HasHorizontalAlignment.ALIGN_CENTER);
		bodyPanel.setCellHorizontalAlignment(dateAvailableLabel, HasHorizontalAlignment.ALIGN_CENTER);
		bodyPanel.setCellHorizontalAlignment(dateAddedLabel, HasHorizontalAlignment.ALIGN_CENTER);
	}

	public boolean updateFromHistoryParameters(String[] params)
	{
		int pId = 0;
		int cId = 0;
		int mId = 0;
		try {
			pId = Integer.parseInt(params[1]);
			cId = Integer.parseInt(params[2]);
			mId = Integer.parseInt(params[3]);
		}
		catch (Exception e) {}

		productModel.update(cId, pId, "TBD");
		StoreComponentController.categoriesComponent.getCategoryModel().update(StoreComponentController.categoriesComponent.getCategoryModel(cId));

		if (StoreComponentController.manufacturersComponent.getManufacturerModel().getId() != mId)
		{
			StoreComponentController.manufacturersComponent.getManufacturerModel().update(StoreComponentController.manufacturersComponent.getManufacturerModelById(mId));
			StoreComponentController.manufacturersComponent.rebuild();
			storeController.getMultipleResultsComponent().addComponent(StoreComponentController.categoriesComponent);
		}

		storeController.getMultipleResultsComponent().addComponent(alsoPurchasedComponent);

		storeController.getMultipleResultsComponent().addComponent(productXSellComponent);

		storeController.getMultipleResultsComponent().addComponent(this);

		//Don't look for new products when sending productcomponent
		CommonSimpleComponent alwaysAskComponent = controller.getComponent("NewProductsComponent", false);
		if (alwaysAskComponent != null) storeController.getMultipleResultsComponent().removeComponent(alwaysAskComponent);

		return super.updateFromHistoryParameters(params);
	}

	public void onBuilt()
	{
		tellAFriendComponent.build();
		manufacturerInfoComponent.build();
		setVisible(true);
	}

	public void build()
	{
		if (productModel.getId() > 0)
		{
			super.build();
		}
		else
		{
			productModel = new DetailedProductModel(0, 0, "");
			try {
				buildFromModel();
			}
			catch (Exception e)
			{
				build(e);
			}
		}
	}

	public void build(JSONValue jsonValue)
	{
		try {
			JSONValue componentValue = CommonUtils.getComponentValue(jsonValue, getHandle());
			if (componentValue != null)
			{
				JSONArray jsonArray;
				if ((jsonArray = componentValue.isArray()) != null)
				{
					JSONValue componentMetaDataValue = CommonUtils.getComponentValue(jsonValue, getHandle() + "MetaData");
					if (componentMetaDataValue != null)
					{
						JSONObject jsonObject;
						if ((jsonObject = componentMetaDataValue.isObject()) != null)
						{
							buildMetaModel(jsonObject);
						}
					}

					buildModel(jsonArray);
					buildFromModel();
				}
				else
				{
					productModel = new DetailedProductModel(0, -1, "");
					buildFromModel();
				}
			}
			else
			{
				productModel = new DetailedProductModel(0, -1, "");
				buildFromModel();
			}
		}
		catch (Exception e)
		{
			build(e);
		}
	}

	protected void buildMetaModel(JSONObject jsonObject) throws Exception
	{
		productMetaModel = new ProductMetaModel(jsonObject);
	}

	protected void buildModel(JSONObject jsonObject) throws Exception
	{		
		productModel = new DetailedProductModel(jsonObject, productMetaModel.getImageWidthMax(), productMetaModel.getImageHeightMax(), true);
	}

	public void buildFromModel() throws Exception
	{
		panel.setText(0, 0, productModel.getName());
		if (productModel.getId() < 1)
		{
			panel.setText(1, 0, "");
		}
		else
		{
			panel.setWidget(1, 0, bodyPanel);

			//Previous Next
			if (productMetaModel.getPrevNextBarLocation() > 0)
			{
				CategoryModel categoryModel = StoreComponentController.categoriesComponent.getCategoryModel(productModel.getCategoryId());
				int[] productIds = categoryModel.getProductIds();
				int total = productIds.length;
				int index = categoryModel.getProductIdIndex(productModel.getId());
				int prevIndex = index -1;
				if (prevIndex < 0) prevIndex = total -1;
				int nextIndex = index + 1;
				if (nextIndex == total) nextIndex = 0;
				prevProductId = productIds[prevIndex];
				nextProductId = productIds[nextIndex];

				String prevNext = "&nbsp;" + storeController.getStoreConstants().ProductComponentProduct() + " " + 
				(index+1) + " " + storeController.getStoreConstants().ProductComponentOf() + " " + total + " " + 
				storeController.getStoreConstants().ProductComponentCategory() + " " + categoryModel.getName() + "&nbsp;";

				if (productMetaModel.getPrevNextBarLocation() == 1 || productMetaModel.getPrevNextBarLocation() == 3)
				{
					prevButtonTop = new PushButton(new Image(getImageCommonDirectory() + "go-previous.png"), new Image(getImageCommonDirectory() + "go-previous_pushed.png"), prevNextClickHandler);
					prevButtonTop.setStyleName(getHandle() + "PrevButton");
					prevButtonTop.addStyleName("ComponentLink");
					nextButtonTop = new PushButton(new Image(getImageCommonDirectory() + "go-next.png"), new Image(getImageCommonDirectory() + "go-next_pushed.png"), prevNextClickHandler);
					nextButtonTop.setStyleName(getHandle() + "NextButton");
					nextButtonTop.addStyleName("ComponentLink");

					InlineHTML prevNextHTMLTop = new InlineHTML(prevNext);

					prevNextPanelTop.clear();
					prevNextPanelTop.add(prevButtonTop);
					prevNextPanelTop.add(prevNextHTMLTop);
					prevNextPanelTop.add(nextButtonTop);
				}

				if (productMetaModel.getPrevNextBarLocation() == 2 || productMetaModel.getPrevNextBarLocation() == 3)
				{
					prevButtonBot = new PushButton(new Image(getImageCommonDirectory() + "go-previous.png"), new Image(getImageCommonDirectory() + "go-previous_pushed.png"), prevNextClickHandler);
					prevButtonBot.setStyleName(getHandle() + "PrevButton");
					prevButtonBot.addStyleName("ComponentLink");
					nextButtonBot = new PushButton(new Image(getImageCommonDirectory() + "go-next.png"), new Image(getImageCommonDirectory() + "go-next_pushed.png"), prevNextClickHandler);
					nextButtonBot.setStyleName(getHandle() + "NextButton");
					nextButtonBot.addStyleName("ComponentLink");

					InlineHTML prevNextHTMLBot = new InlineHTML(prevNext);

					prevNextPanelBot.clear();
					prevNextPanelBot.add(prevButtonBot);
					prevNextPanelBot.add(prevNextHTMLBot);
					prevNextPanelBot.add(nextButtonBot);
				}
			}

			//Name, Model and Price
			List<PriceBreakModel> priceBreaks = productModel.getPriceBreaks();
			int sz = priceBreaks.size();
			nameLabel.setHTML("<span class=\"" + getHandle() + "Name" +"\">" + productModel.getName() + "</span>" +
					"<br/><span class=\"" + getHandle() + "Model" +"\">[" + productModel.getModel() + "]</span>");
			String price = CommonUtils.productPriceDisplay (StoreComponentController.currenciesComponent.getCurrencyModel(), productModel.getPrice(), productModel.getPrice(), productModel.getSpecialPrice());
			if (productModel.getWeight() < 0.00001 && sz == 0 && !productModel.isVirtual()) price += "<br/><span class=\"" + getHandle() + "Shipping" +"\">Free Shipping!</span>";

			int qtyBlocks = 1;
			if (productModel.getQuantityBlocks() > 1)qtyBlocks = productModel.getQuantityBlocks();
			if (sz == 0)
			{
				priceLabel.setHTML(price);
				headingPanel.setWidget(0, 1, priceLabel);
				headingPanel.setWidget(1, 0, new InlineLabel(""));
			}
			else
			{
				priceGrid = new Grid(3, sz + 2);
				priceGrid.addStyleName(getHandle() + "PriceGrid");

				for (int k=0; k<priceGrid.getColumnCount(); k++)
				{
					priceGrid.getCellFormatter().addStyleName(0, k, getHandle() + "PriceGridHeading");
					priceGrid.getCellFormatter().addStyleName(0, k, getHandle() + "PriceGridCell");
					priceGrid.getCellFormatter().addStyleName(1, k, getHandle() + "PriceGridCell");
					priceGrid.getCellFormatter().addStyleName(2, k, getHandle() + "PriceGridCell");

				}
				priceGrid.getCellFormatter().setHorizontalAlignment(2, 1, HasHorizontalAlignment.ALIGN_CENTER);

				priceGrid.setText(0, 0, storeController.getStoreConstants().ProductComponentPriceGridQuantity());
				priceGrid.setText(1, 0, storeController.getStoreConstants().ProductComponentPriceGridPrice());
				priceGrid.setText(2, 0, storeController.getStoreConstants().ProductComponentPriceGridSavings());

				priceGrid.setText(0, 1, String.valueOf(qtyBlocks) + "+");
				priceGrid.setHTML(1, 1, price);
				priceGrid.setText(2, 1, "-");

				double dblPrice = productModel.getPrice();
				for (int i = 0; i< sz; i++)
				{
					PriceBreakModel priceBreak = priceBreaks.get(i);
					int qty = priceBreak.getQuantity();
					double dblDiscountPrice = priceBreak.getPrice();
					double savings = (dblPrice - dblDiscountPrice) / dblPrice;

					String discountPrice = CommonUtils.productPriceDisplay (StoreComponentController.currenciesComponent.getCurrencyModel(), dblDiscountPrice, dblDiscountPrice, productModel.getSpecialPrice());
					priceGrid.setText(0, i+2, String.valueOf(qty) + "+");
					priceGrid.setHTML(1, i+2, discountPrice);
					priceGrid.setText(2, i+2, fmt.format(savings));
					priceGrid.getCellFormatter().addStyleName(0, i+2, getHandle() + "PriceGridHeading");
					priceGrid.getCellFormatter().addStyleName(0, i+2, getHandle() + "PriceGridCell");
					priceGrid.getCellFormatter().addStyleName(1, i+2, getHandle() + "PriceGridCell");
					priceGrid.getCellFormatter().addStyleName(2, i+2, getHandle() + "PriceGridCell");
					priceGrid.getCellFormatter().setHorizontalAlignment(2, i+2, HasHorizontalAlignment.ALIGN_CENTER);

				}
				headingPanel.setWidget(1, 0, priceGrid);
				String shipping = "";
				if (productModel.getWeight() < 0.00001 && !productModel.isVirtual()) shipping = "<span class=\"" + getHandle() + "Shipping" +"\">Free Shipping!</span>";
				headingPanel.setWidget(0, 1, new InlineHTML(shipping));

			}

			//Product Description and Image
			images = productModel.getImages();
			imageSizes = productModel.getImageSizes();
			int sz1 = images.size();
			int sz2 = 7;
			for (int i = 0; i< sz2; i++)
			{
				InlineHTML imageLabel = (InlineHTML)imagesSelectionPanel.getWidget(i);
				if (i < sz1)
					imageLabel.setVisible(true);
				else
					imageLabel.setVisible(false);
			}
			if (sz1 == 1)
			{
				InlineHTML imageLabel = (InlineHTML)imagesSelectionPanel.getWidget(0);
				imageLabel.setVisible(false);
			}

			if (sz1 > 1)
			{
				verticalImagePanel.addStyleName("BorderImage");
			}
			else
			{
				verticalImagePanel.removeStyleName("BorderImage");
			}

			image.setUrl(StoreUtils.getImageProductsDirectory() + images.get(0));
			String[] imageSize = imageSizes.get(0);
			image.setSize(imageSize[0], imageSize[1]);
			image.setTitle(productModel.getName());
			String descriptionText = productModel.getDescription();
			if (!productModel.isStatus()) {
				descriptionText = "<span class=\"WarningLabel\">" + storeController.getStoreConstants().ProductComponentUnpublished() + "</span><br/>" + descriptionText;
			}
			descriptionLabel.setHTML(descriptionText);
			List<AttributeModel> attributes = productModel.getAttributes();

			//URL
			String strUrl = productModel.getUrl();
			if (strUrl != null && strUrl.length() > 0)
			{
				urlAnchor.setText("Click Here");
				urlAnchor.setHref(strUrl);
			}
			else
			{
				urlAnchor.setText("");
				urlAnchor.setHref("");
			}
			//Options
			optionsPanel.clear();
			optionsListBoxList = new ArrayList<ListBox>();
			optionsHash = new HashMap<String, AttributeValueModel>();

			sz = attributes.size();
			if (sz > 0)
			{
				optionsPanel.add(new InlineLabel(storeController.getStoreConstants().ProductComponentAvailableOptions()));
				Grid optionsGrid = new Grid(sz, 2);
				optionsPanel.add(optionsGrid);
				for (int i = 0; i< sz; i++)
				{
					AttributeModel attribute = attributes.get(i);
					optionsGrid.setText(i, 0, attribute.getName());
					ListBox listBox = new ListBox();
					optionsListBoxList.add(listBox);
					optionsGrid.setWidget(i, 1, listBox);
					List<AttributeValueModel> values = attribute.getValues();
					int vsz = values.size();
					NumberFormat fmt = NumberFormat.getCurrencyFormat(StoreComponentController.currenciesComponent.getCurrencyModel().getCode());
					for (int j= 0; j< vsz; j++)
					{
						AttributeValueModel value = values.get(j);
						String valueName = value.getName();
						if (value.getPrice() != 0)
						{
							double valuePrice = value.getPrice() * StoreComponentController.currenciesComponent.getCurrencyModel().getValue();

							valueName = valueName +  " (" + value.getPrefix() + fmt.format(valuePrice) + ")";
						}
						String valueId = String.valueOf(value.getAttributeId()) + "_" + String.valueOf(value.getId());
						listBox.addItem(valueName, valueId);
						optionsHash.put(valueId, value);
						if (j == 0)
						{
							listBox.setSelectedIndex(j);
						}
					}
				}
			}

			String reviewTag = "0";
			int nreviews = productModel.getNumberOfReviews();
			double averageRating = productModel.getReviewsAverage();

			if (nreviews == 0) {
				numberOfReviewsHTML.setHTML("No reviews exist, if you have purchased this product, please create a review. ");
				reviewImage.setUrl(this.getImageCommonDirectory() + "stars_0.gif");
			}
			else {
				numberOfReviewsHTML.setHTML("Average review rating: ");
				if (averageRating < .75) reviewTag = "0";
				else if (averageRating < 1.25) reviewTag = "1";
				else if (averageRating < 1.75) reviewTag = "1_5";
				else if (averageRating < 2.25) reviewTag = "2";
				else if (averageRating < 2.75) reviewTag = "2_5";
				else if (averageRating < 3.25) reviewTag = "3";
				else if (averageRating < 3.75) reviewTag = "3_5";
				else if (averageRating < 4.25) reviewTag = "4";
				else if (averageRating < 4.75) reviewTag = "4_5";
				else reviewTag = "5";
			}
			reviewImage.setUrl(this.getImageCommonDirectory() + "stars_" + reviewTag + ".gif");

			//Date Added Label
			if (productModel.getDateAvailable() != null && productModel.getDateAvailable().after(new Date()))
			{
				dateAvailableLabel.setText(storeController.getStoreConstants().ProductComponentAvailableDateText() + " " + DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.DATE_MEDIUM).format(productModel.getDateAvailable()));
				dateAddedLabel.setText("");
			}
			else
			{
				dateAvailableLabel.setText("");
				dateAddedLabel.setText(storeController.getStoreConstants().ProductComponentCreateDateText() + " " + DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.DATE_MEDIUM).format(productModel.getDateAdded()));
			}
			//Shopping Cart
			quantityTextBox.setText(String.valueOf(qtyBlocks));
		}

		onBuilt();
	}

	protected ClickHandler prevNextClickHandler = new ClickHandler() {
		public void onClick(ClickEvent event) {
			PushButton button = (PushButton)event.getSource();
			String sname = button.getStyleName();
			int selectedProductId = 0;
			if (sname.startsWith(getHandle() + "PrevButton"))
			{
				selectedProductId = prevProductId;
			}
			else if (sname.startsWith(getHandle() + "NextButton"))
			{
				selectedProductId = nextProductId;
			}

			onSelection("ProductComponent--" + selectedProductId + "--" + productModel.getCategoryId()
					+ "--" + StoreComponentController.manufacturersComponent.getManufacturerModel().getId());
		}
	};

	protected ClickHandler cartClickHandler = new ClickHandler() {
		public void onClick(ClickEvent event) {
			StoreComponentController.enableWait();
			DetailedProductModel cartProductModel = new DetailedProductModel(0, 0, "");
			cartProductModel.update(productModel);

			//Retrieve Quantity and set on cartProductModel
			String strQty = quantityTextBox.getText();
			int qty = 1;
			try {qty = Integer.parseInt(strQty);}
			catch(Exception e) {
			}
			cartProductModel.setCartQuantity(qty);
			cartProductModel.setCartQuantityMax(productMetaModel.getCartQuantityMax());
			quantityTextBox.setText(String.valueOf(cartProductModel.getCartQuantity()));

			//Place Options on cartProductModel
			cartProductModel.setAttributes(productModel.getAttributes());
			cartProductModel.setPriceBreaks(productModel.getPriceBreaks());
			cartProductModel.clearCartOptions();
			if (optionsListBoxList.size() > 0)
			{
				for (int i = 0; i < optionsListBoxList.size(); i++)
				{
					ListBox listBox = optionsListBoxList.get(i);
					int index = listBox.getSelectedIndex();
					String valueId = listBox.getValue(index);
					AttributeValueModel model = optionsHash.get(valueId);
					cartProductModel.addCartOptions(model);
				}
			}

			try {
				if (StoreComponentController.cartComponent == null) StoreComponentController.cartComponent = (CartComponent)controller.getComponent("CartComponent");
				StoreComponentController.cartComponent.getCartModel().addProduct(cartProductModel);
			}
			catch(TooManyItemsInCartException e)
			{
				Window.alert(storeController.getStoreConstants().CartComponentTooManyItems());
			}

			if (productMetaModel.isDisplayCart())
			{
				onSelection("CartComponent");
			}

			StoreComponentController.disableWait();
		}
	};

	protected ClickHandler reviewsClickHandler = new ClickHandler() {
		public void onClick(ClickEvent event) {
			if (productModel.isHasReviews())
			{
				onSelection("ProductReviewsComponent--" + productModel.getId() + "--" + productModel.getCategoryId()
						+ "--" + StoreComponentController.manufacturersComponent.getManufacturerModel().getId());
			}
			else
			{
				onSelection("CreateProductReviewComponent--0--" + productModel.getId() + "--" + productModel.getCategoryId()
						+ "--" + StoreComponentController.manufacturersComponent.getManufacturerModel().getId() + "--" + ProductReviewModel.PRODUCT);
			}
		}
	};

	protected ClickHandler imageClickHandler = new ClickHandler() {
		public void onClick(ClickEvent event) {
			DialogBox dialogBox = createImageDialogBox();
			dialogBox.center();
			dialogBox.show();

		}
	};

	public ProductModel getProductModel() {
		return productModel;
	}

	protected DialogBox createImageDialogBox() {
		final DialogBox dialogBox = new DialogBox();
		dialogBox.setText(productModel.getName());
		VerticalPanel dialogContents = new VerticalPanel();
		dialogContents.setSpacing(4);
		dialogBox.setWidget(dialogContents);
		dialogImage = new Image();
		FlowPanel dialogImagesSelectionPanel = new FlowPanel();

		int sz1 = images.size();

		if (sz1 > 1)
		{
			InlineHTML dialogImage0Label = new InlineHTML("1");
			dialogImage0Label.setStyleName("ComponentLink");
			dialogImage0Label.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					dialogImage.setUrl(StoreUtils.getImageProductsDirectory() + images.get(0));
					String[] imageSize = imageSizes.get(0);
					int width = Integer.parseInt(imageSize[0]) * 2;
					int height = Integer.parseInt(imageSize[1]) * 2;
					if (height > maxHeight) 
					{
						double ratio = maxHeight / height;
						width = (int) Math.round(ratio * width);
						height = maxHeight;
					}
					dialogImage.setSize(String.valueOf(width), String.valueOf(height));
				}
			});
			dialogImagesSelectionPanel.add(dialogImage0Label);

			InlineHTML dialogImage1Label = new InlineHTML("&nbsp;2");
			dialogImage1Label.setStyleName("ComponentLink");
			dialogImage1Label.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					dialogImage.setUrl(StoreUtils.getImageProductsDirectory() + images.get(1));
					String[] imageSize = imageSizes.get(1);
					int width = Integer.parseInt(imageSize[0]) * 2;
					int height = Integer.parseInt(imageSize[1]) * 2;
					if (height > maxHeight) 
					{
						double ratio = maxHeight / height;
						width = (int) Math.round(ratio * width);
						height = maxHeight;
					}
					dialogImage.setSize(String.valueOf(width), String.valueOf(height));
				}
			});
			dialogImagesSelectionPanel.add(dialogImage1Label);
		}
		if (sz1 > 2)
		{
			InlineHTML dialogImage2Label = new InlineHTML("&nbsp;3");
			dialogImage2Label.setStyleName("ComponentLink");
			dialogImage2Label.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					dialogImage.setUrl(StoreUtils.getImageProductsDirectory() + images.get(2));
					String[] imageSize = imageSizes.get(2);
					int width = Integer.parseInt(imageSize[0]) * 2;
					int height = Integer.parseInt(imageSize[1]) * 2;
					if (height > maxHeight) 
					{
						double ratio = maxHeight / height;
						width = (int) Math.round(ratio * width);
						height = maxHeight;
					}
					dialogImage.setSize(String.valueOf(width), String.valueOf(height));
				}
			});
			dialogImagesSelectionPanel.add(dialogImage2Label);
		}
		if (sz1 > 3)
		{
			InlineHTML dialogImage3Label = new InlineHTML("&nbsp;4");
			dialogImage3Label.setStyleName("ComponentLink");
			dialogImage3Label.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					dialogImage.setUrl(StoreUtils.getImageProductsDirectory() + images.get(3));
					String[] imageSize = imageSizes.get(3);
					int width = Integer.parseInt(imageSize[0]) * 2;
					int height = Integer.parseInt(imageSize[1]) * 2;
					if (height > maxHeight) 
					{
						double ratio = maxHeight / height;
						width = (int) Math.round(ratio * width);
						height = maxHeight;
					}
					dialogImage.setSize(String.valueOf(width), String.valueOf(height));
				}
			});
			dialogImagesSelectionPanel.add(dialogImage3Label);
		}
		if (sz1 > 4)
		{
			InlineHTML dialogImage4Label = new InlineHTML("&nbsp;5");
			dialogImage4Label.setStyleName("ComponentLink");
			dialogImage4Label.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					dialogImage.setUrl(StoreUtils.getImageProductsDirectory() + images.get(4));
					String[] imageSize = imageSizes.get(4);
					int width = Integer.parseInt(imageSize[0]) * 2;
					int height = Integer.parseInt(imageSize[1]) * 2;
					if (height > maxHeight) 
					{
						double ratio = maxHeight / height;
						width = (int) Math.round(ratio * width);
						height = maxHeight;
					}
					dialogImage.setSize(String.valueOf(width), String.valueOf(height));
				}
			});
			dialogImagesSelectionPanel.add(dialogImage4Label);
		}
		if (sz1 > 5)
		{
			InlineHTML dialogImage5Label = new InlineHTML("&nbsp;6");
			dialogImage5Label.setStyleName("ComponentLink");
			dialogImage5Label.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					dialogImage.setUrl(StoreUtils.getImageProductsDirectory() + images.get(5));
					String[] imageSize = imageSizes.get(5);
					int width = Integer.parseInt(imageSize[0]) * 2;
					int height = Integer.parseInt(imageSize[1]) * 2;
					if (height > maxHeight) 
					{
						double ratio = maxHeight / height;
						width = (int) Math.round(ratio * width);
						height = maxHeight;
					}
					dialogImage.setSize(String.valueOf(width), String.valueOf(height));
				}
			});
			dialogImagesSelectionPanel.add(dialogImage5Label);
		}
		if (sz1 > 6)
		{
			InlineHTML dialogImage6Label = new InlineHTML("&nbsp;7");
			dialogImage6Label.setStyleName("ComponentLink");
			dialogImage6Label.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					dialogImage.setUrl(StoreUtils.getImageProductsDirectory() + images.get(6));
					String[] imageSize = imageSizes.get(6);
					int width = Integer.parseInt(imageSize[0]) * 2;
					int height = Integer.parseInt(imageSize[1]) * 2;
					if (height > maxHeight) 
					{
						double ratio = maxHeight / height;
						width = (int) Math.round(ratio * width);
						height = maxHeight;
					}
					dialogImage.setSize(String.valueOf(width), String.valueOf(height));
				}
			});
			dialogImagesSelectionPanel.add(dialogImage6Label);
		}
		dialogImage.setUrl(StoreUtils.getImageProductsDirectory() + images.get(0));
		String[] imageSize = imageSizes.get(0);
		int width = Integer.parseInt(imageSize[0]) * 2;
		int height = Integer.parseInt(imageSize[1]) * 2;
		if (height > maxHeight) 
		{
			double ratio = (maxHeight * 1.0) / height;
			width = (int)Math.round(ratio * width);
			height = maxHeight;
		}
		dialogImage.setSize(String.valueOf(width), String.valueOf(height));
		dialogImage.setTitle(productModel.getName());
		dialogContents.add(dialogImage);
		dialogContents.setCellHorizontalAlignment(dialogImage, HasHorizontalAlignment.ALIGN_CENTER);

		dialogContents.add(dialogImagesSelectionPanel);

		// Add a close button at the bottom of the dialog
		Button closeButton = new Button(controller.getCommonConstants().Close(),
				new ClickHandler() {
			public void onClick(ClickEvent event) {
				dialogBox.hide();
			}
		});
		dialogContents.add(closeButton);
		dialogContents.setCellHorizontalAlignment(closeButton,
				HasHorizontalAlignment.ALIGN_LEFT);
		dialogBox.setStyleName(getHandle() + "DialogBox");

		// Return the dialog box
		return dialogBox;
	}

}
